﻿#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
//int main()
//{
//	int a[3][4] = { 0 };//此时创建一个二维数组，3行4列的二维数组，全部初始化为0
//	printf("%zd\n", sizeof(a));//数组名单独放在sizeof里面表示整个数组，这里计算整个数组的大小    48
//	printf("%zd\n", sizeof(a[0][0]));//行标为0列标为0的元素，也就是第一个元素，   4
//	printf("%zd\n", sizeof(a[0]));//a[0]是第一个一维数组的数组名，数组名单独放在sizeof里面，表示整个数组，    16
//	printf("%zd\n", sizeof(a[0] + 1));//a[0]是第一个和以为数组的数组名，数组名没有单独放在sizeof里面，这里的数组名表示数组首元素地址
//	//数组首元素地址+1跳过一个元素，得到下标为1的地址   是地址就是4/8
//	printf("%zd\n", sizeof(*(a[0] + 1)));//数组名没有单独放置sizeof内部，这里的数组名表示首元素地址，首元素地址+1的到下一个元素的地址
//	//都系啊一个元素的地址*得到下一个元素，    4
//	printf("%zd\n", sizeof(a + 1));//这里的数组名没有单独放在sizeof里面，这里的数组名表示数组首元素地址，而这是一个二维数组，二维数组是一维数组的数组
//	//二维数组的每个元素是一个一维数组，所以二维数组首元素地址，就是第一个一维数组的地址，一维数组地址+1跳过一个一维数组，得到第二个一维数组的地址
//	//是地址就是    4/8
//	printf("%zd\n", sizeof(*(a + 1)));//在这里的数组名没有单独放在sizeof里面，所以这里的数组名表示首元素地址，二维数组的每个元素是一个一维数组
//	//所以是第一个以为数组的地址，一维数组地址+1，跳过一个一维数组，得到第二个一维数组的地址，数组的地址*，得到数组名，数组名单独放在sizeof里面
//	//表示整个数组         16         *&数组名  == 数组名
//	//指针类型决定了指针在解引用时有多大访问权限
//	//而数组指针的指针类型是int（*）[4]，所以数组指针在*解引用时访问整个数组
//	printf("%zd\n", sizeof(&a[0] + 1));//a[0]是第一个以为数组的数组名，&数组名，这里的数组名表示整个数组，取出整个数组的地址
//	//数组的地址+1，跳过整个数组，得到第二个一维数组的地址，是地址就是 4/8
//	printf("%zd\n", sizeof(*(&a[0] + 1)));//a[0]是第一个一维数组的数组名，&数组名，这里的数组名表示整个数组，取出第一个一维数组的地址
//	//一维数组地址+1得到第二个一维数组的地址，再对一维数组的地址*   *&arr == arr，所以这里最后得到第二个一维数组的数组名
//	//数组名单独放在sizeof里面表示整个数组      16
//	printf("%zd\n", sizeof(*a));//a没有单独放在sizeof内部，所以这这里的数组名表示首元素地址，对首元素地址*，就是对第一个一维数组*
//	//得到第一个一维数组的数组名，数组名单独放在sizeof里面，这里的数组名表示整个数组，   16
//	printf("%zd\n", sizeof(a[3]));//二维数组一共三行，行标最多为2，但是这里是3，这里也是一个一维数组的数组名，数组名单独放在sizeof里面
//	//就表示整个数组，而sizeof不会真是去访问这里是否有什么数据，是否真实存在，只会根据它的类型计算出，创建该类型所需要的空间
//	//  16
//	return 0;
//}
//////48  4  16  4/8  4 4/8 16 4/8 16 16 16
//int main()
//{
//	int a[5] = { 1, 2, 3, 4, 5 };//创建一个一维数组，大小为5，存放1，2，3，4，5
//	int* ptr = (int*)(&a + 1);//&数组名，这俩爹数组名表示整个数组，取出整个数组的地址数组地址+1跳过整个数组
//	//指针的类型决定了指针+-整数向前或者向后都到距离，然后将这个指针强制类型转换为int*
//	//强制类型转换本质上是创一个强转类型的临时变量来存放被强转的数据
//	//被强转的数据本质上的类型没有改变
//	printf("%d,%d", *(a + 1), *(ptr - 1));//数组名表示数组首元素地址，首元素地址+1跳过一个元素， 2
//	//ptr向后走一个整型，也就是5的地址，*     5
//	return 0;
//}
////2 5
//在X86环境下 
//假设结构体的⼤⼩是20个字节 
////程序输出的结果是啥？ 
//struct Test     //创建一个结构体，该结构体大小为20个字节
//{
//    int Num;
//	char* pcName;
//	short sDate;
//	char cha[2];
//	short sBa[4];
//}*p = (struct Test*)0x100000;//创建结构体指针变量p，将0x100000强制类型转化为结构体指针，然后赋值给结构体指针变量p
//int main()
//{                           //c语言里面乘号用*   这里的0x表示十六进制
//	printf("%p\n", p + 0x1);//p作为结构体指针变量，+1跳过一个结构体，指针类型决定了指针+-整数向前或者向后走多大距离，一个结构体的大小为20
//	//所以向前走20个字节 0x100020
//	printf("%p\n", (unsigned long)p + 0x1);//将p强制类型转化为无符号长整型，整型+1，0x100001
//	printf("%p\n", (unsigned int*)p + 0x1);//将p结构体指针强制类型转换为无符号整型指针，整型指针+1跳过一个整型
//	//0x100004
//	return 0;
////}
//int main()
//{
//	int a[3][2] = { (0, 1), (2, 3), (4, 5) };//创建一个二维数组，二维数组里面初始化用的逗号表达式
//	//逗号表达式，从左向右依次执行，最后一个表达式的结果，就是整个逗号表达式的结果，所以初始化为1，3，5
//	int* p;//创建一个整型指针变量p
//	p = a[0];//将首元素第一个一维数组的数组名给p，也就是第一个一维数组的首元素地址给p
////	printf("%d", p[0]);//*（p+0）1
////	return 0;
////}
//int main()
//{
//	int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };//创建一个二维数组，2行5列
//	int* ptr1 = (int*)(&aa + 1);//&数组名，这里的数组名表数字整个数组，取出整个数组的地址，整个数组的地址+1跳过整个数组
//	//指针类型决定了指针+-整数向前或者向后走多大距离，然后将这个指针强制类型转换为int*，然后赋值给ptr1
//	int* ptr2 = (int*)(*(aa + 1));//这里的数组名表示首元素地址，也就是第一个一维数组的地址，数组地址+1跳过整个数组，也就是第二个一维数组的地址
//	//数组地址*  得到数组名，数组名表示数组首元素地址，也就是第二个一维数组的首元素地址，然后强制类型转换为int*，其实很没必要
//	//一维数组的首元素地址本来就是int*
//int main()
//{
//	char* a[] = { "work","at","alibaba" };//创建一个字符指针数组，数组大小为3，用字符串初始化字符指针，也就是将字符串首字符的地址赋值给字符指针
//	char** pa = a;//指针数组在创建的时候也会申请空间，将这个指针数组的地址赋值给pa，pa里面存放着指针的指针也就是二级指针变量
//	pa++;//pa的指针类型为char**，指针类型决定了指针+-整数向前或者向后走多大距离，pa+1 向前走4/8个字节
//	printf("%s\n", *pa);//at
//	return 0;//n级指针+-整数跳过4/8个字节
////}
//int main()
//{
//	char* c[] = { "ENTER","NEW","POINT","FIRST" };
//	char** cp[] = { c + 3,c + 2,c + 1,c };
//	char*** cpp = cp;
//	printf("%s\n", **++cpp);//point
//	printf("%s\n", *-- * ++cpp + 3);//ER
//	printf("%s\n", *cpp[-2] + 3);//first
//	printf("%s\n", cpp[-1][-1] + 1);//
//	return 0;
//}
//字符串是可以赋值给字符指针的，将字符串首字符的地址赋值给字符指针，字符串在内存中是连续存储的，所以字符指针指向字符串的首字符，
//也就是变相指向了字符串
//strlen计算字符串大小，也就是计算字符串\0之前的字符个数
//strlen模拟实现
//1.
#include<assert.h>
#include<stdio.h>
//size_t my_strlen1(const char* str)
//{
//	assert(str);
//	size_t count = 0;
//	while (*str)
//	{
//		str++;
//		count++;
//	}
//	return count;
//}
//
//int main()
//{
//	char arr[] = "abcdefgi";
//	size_t len = my_strlen1(arr);
//	printf("%zd", len);
//	return 0;
//}
//2.
//size_t my_strlen2(const char* str)
//{
//  assert(str);
//	char* ch = str;
//	while (*str)
//	{
//		str++;
//	}
//	return str - ch;   //指针——指针，两个指针之间的元素个数
//}
//
//int main()
//{
//	char arr[] = "abcdefgi";
//	size_t len = my_strlen2(arr);
//	printf("%zd", len);
//	return 0;
//}
//3.
//int my_strlen(const char* str)
//{
//	assert(str);
//	if (*str == '\0')
//		return 0;
//	else
//		return 1 + my_strlen(str + 1);
//}
//
//size_t my_strlen3(const char* str)
//{
//	assert(str);
//	if (*str == '\0')
//		return 0;
//	else
//		return 1 + my_strlen3(str + 1);
//}
//
//  int main()
//{
//	char arr[] = "abcdefgi";
//	size_t len = my_strlen3(arr);
//	printf("%zd", len);
//	return 0;
//}

